using UnityEngine;
using System.Collections;
using Game;
using System.Collections.Generic;
using Game.Global.Helper;
using System;

/// <summary>
/// 所有游戏运行时的游戏组SceneObjGroup的顶级父物体，及其管理器。
/// 在Runtime中，会根据距离远近决定是否生成组，或是获得附近的组；
/// 对有变动的物体组，会进行记录和保存
/// </summary>
/// <remarks></remarks>
public class SceneObjGroupManager : MonoBehaviour
{
    public static SceneObjGroupManager Instance { get; private set; }

    /// <summary>
    /// 用于保存玩家在运行时中创建的ObjGroup的位置信息的文件夹
    /// </summary>
    const string C_UserObjGroupFolder = "UserCreatedGroupData";

    Transform m_transform;

    /// <summary>
    /// 存储ObjSettingData中的Prefab的序号的索引器，加快搜索
    /// </summary>
    Dictionary<GameObject, int> m_dictPrefObjDataIndexer;

    [Tooltip("附加了最齐全的Prefab，用于游戏运行时创建新的组")]
    [SerializeField] GameObject autoDisableGroupTemplate;

    [SerializeField] SceneObjDataSetting[] objSettingDatas = new SceneObjDataSetting[8];

    //TODO:将各个单独的DataManager直接搬运到此处
    //SceneObj组
    //TODO:这样可以快速且省空间找Prefab
    void Awake()
    {
        if (Instance != null)
        {
            Debug.LogError(this.name + " Shown in scene for multiple times.");
            return;
        }

        #region EDITOR CHECK
#if UNITY_EDITOR
        if (autoDisableGroupTemplate == null)
        {
            Debug.LogError("Scene Obj prefab was not set");
        }
        else
        {
            if (autoDisableGroupTemplate.GetComponent<Editor_ObjData>() == null)
            {
                Debug.LogError("Template has no data manager set.");
            }
            else if (autoDisableGroupTemplate.GetComponent<SceneObjGroup>() == null)
            {
                Debug.LogError("No autoDisable script attached.");
            }
        }

        if (GameObject.FindObjectsOfType<SceneObjGroup>().Length > this.transform.childCount)
        {
            Debug.LogError("Maybe you should make group objects as this obj's children");
        }

#endif
        #endregion

        Instance = this;
        m_transform = this.transform;

        SetOrCreateObjGroups();

        SceneObjGroup.InitBuffers(GetAllGameObjPrefabs());
    }

    #region Public Area

#if UNITY_EDITOR
    [ContextMenu("Generate Preview For Prefabs")]
    /// <summary>
    /// 编辑器调用：生成预制物体的预览图
    /// </summary>
    public void Editor_GenPreviewForPrefabs()
    {
        //--一键制作预览图
        string path = FileHelper.GetResourcesPath("ObjGrpPfbPreview");

        bool hasSaved = false;
        //获得物体及其预览：
        GameObject[] objs = GetAllGameObjPrefabs();

        for (int j = 0; j < objs.Length; j++)
        {
            if (objs[j] != null)
            {
                //获得预览，但是由于缓存存在，且不会自动刷新的缘故，总会获得旧的Preview：
                Texture2D texSrc = UnityEditor.AssetPreview.GetAssetPreview(objs[j]);
                
                if (texSrc != null)
                {
                    //--拷贝预览：
                    Texture2D texDuplicated = new Texture2D(texSrc.width, texSrc.height);
                    texDuplicated.SetPixels(texSrc.GetPixels());
                    texDuplicated.mipMapBias = -1.5F;
                    texDuplicated.Apply();

                    byte[] imagebytes = null;

                    try
                    {
                        imagebytes = texDuplicated.EncodeToPNG();
                        texDuplicated.Compress(false);                                            //对屏幕缓存进行压缩，每次运行时只能一次
                    }
                    catch
                    {
                        Debug.LogWarning("Could not encode to JPG. Reopen unity & try again.");
                    }

                    var saveFile = string.Format("{0}/{1}.png", path, j);
                    if (imagebytes != null)
                    {
                        System.IO.File.WriteAllBytes(saveFile, imagebytes);//存储png图
                        hasSaved = true;
                    }
                }
            }
        }

        if (hasSaved)
        {
            Debug.Log("Preview of prefabs was saved to: "+path);
        }
        else
        {
            Debug.Log("Nothing to save.");
        }
        
    }
#endif

    /// <summary>
    /// 获得所有设定信息中的游戏物体Prefabs
    /// </summary>
    /// <returns>The all game object prefabs.</returns>
    public GameObject[] GetAllGameObjPrefabs()
    {
        GameObject[] objects = new GameObject[objSettingDatas.Length];
        for (int i = 0; i < objects.Length; i++)
        {
            objects[i] = objSettingDatas[i] == null ? null : objSettingDatas[i].prefabObj;
        }
        return objects;
    }

    /// <summary>
    /// 获得Prefab物体在SettingData中的存储位置，无则返回-1
    /// </summary>
    /// <returns>The object prefab index.</returns>
    /// <param name="objPrefab">Object prefab.</param>
    public int GetObjPrefabIndex(GameObject objPrefab)
    {
        if (m_dictPrefObjDataIndexer == null)
        {
            m_dictPrefObjDataIndexer = new Dictionary<GameObject, int>();
        }
        else if (m_dictPrefObjDataIndexer.ContainsKey(objPrefab))
        {
            return m_dictPrefObjDataIndexer[objPrefab];
        }

        var objs = GetAllGameObjPrefabs();
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i] == objPrefab)
            {
                //--存储索引，加快下次搜索
                m_dictPrefObjDataIndexer[objPrefab] = i;
                return i;
            }
        }

        return -1;
    }

    /// <summary>
    /// 获得所有的设定信息，使用之前请确保已经申请过存储空间
    /// </summary>
    /// <param name="storageType"></param>
    /// <returns></returns>
    public SceneObjDataSetting[] GetObjSettingData()
    {
        return objSettingDatas;
    }

    /// <summary>
    /// 获得某个序号下的ObjDataSetting
    /// </summary>
    /// <returns>The object setting data.</returns>
    /// <param name="index">Index.</param>
    public SceneObjDataSetting GetObjSettingData(int index)
    {
        return objSettingDatas[index];
    }

    /// <summary>
    /// 遍历已经存储的Prefabs，找出某个Prefab对应的Data（含序号）
    /// </summary>
    /// <returns>The object setting data.</returns>
    /// <param name="objPrefab">Object's prefab.</param>
    public SceneObjDataSetting GetObjSettingData(GameObject objPrefab)
    {
        for (int i = 0; i < objSettingDatas.Length;i++)
        {
            if(objSettingDatas[i].prefabObj == objPrefab)
            {
                return objSettingDatas[i];
            }
        }
        Debug.LogError("Cannot get objSettingData for " + objPrefab.name);
        return null;
    }

    /// <summary>
    /// 扩充数组容量,要使用时必须先扩充出来数组空间
    /// </summary>
    /// <param name="objsArray">目标数组</param>
    /// <param name="expandSize">扩充出来的目标长度</param>
    internal void ExpandGOArrayIfNeed(int expandSize)
    {
        if (expandSize != objSettingDatas.Length)
        {
            SceneObjDataSetting[] tmp = objSettingDatas;
            //--新建一波新的，再把旧数据拷贝
            objSettingDatas = new SceneObjDataSetting[expandSize];

            int countToCopy = tmp.Length;
            if (tmp.Length > expandSize)
            {
                countToCopy = expandSize;
            }


            for (int i = 0; i < countToCopy; i++)
            {
                objSettingDatas[i] = Game.Global.Helper.ClassHelper.Copy(tmp[i]);
            }

            //--因为是class数组，所以需要初始化新的实例
            for (int i = countToCopy; i < expandSize; i++)
            {
                objSettingDatas[i] = new SceneObjDataSetting();
            }
        }
    }

    public void GenerateObjToGroup(int objDataIndex,Vector3 genPosition)
    {
        float groupRange = 1000;
        //TODO:生成物体、取参数
        //获得最近的组，如果无，则生成组：
        var parentScript = GetObjGroup(genPosition, groupRange);
        if (parentScript== null)
        {
            parentScript = GenerateGroup(genPosition);
        }

        var objData = GetObjSettingData(objDataIndex);
        var objCreated =Instantiate(objData.prefabObj, genPosition, Quaternion.identity, parentScript.transform);
        parentScript.SetNewObjAcordingToSetting(objCreated, parentScript.ObjGroupManager.transform, objData);

        //将之纳入组管理中，并放到变更List中
        parentScript.SetChangedInRuntime();
    }

    public void DeleteObj(GameObject obj)
    {
        //获得物体的父物体中的组物体
        var parentScript = obj.GetComponentInParent<SceneObjGroup>();
        parentScript.DeleteObj(obj);

        //将之删除，并将组标为变更
        parentScript.SetChangedInRuntime();
    }

    #endregion

    #region Private Area

    /// <summary>
    /// 对于之前被玩家更改的ObjGroup设置，和未创建的ObjGroup进行创建和设置
    /// </summary>
    private void SetOrCreateObjGroups()
    {
        //Get Files Info
        string[] groupFilesNames;

        //--获得用户创建的ObjGroup的数据文件：
        FileHelper.GetFilesAt(SceneObjGroup.C_DetailsPathInRes, false, out groupFilesNames);//不带扩展名
        if (groupFilesNames != null && groupFilesNames.Length > 0)
        {
            //获得现有的所有ObjGroup：
            var childrenGroups = new Dictionary<int, SceneObjGroup>();
            var childCount = m_transform.childCount;
            for (int i = 0; i < childCount; i++)
            {
                var childTrans = m_transform.GetChild(i);
                var childScript = childTrans.GetComponent<SceneObjGroup>();
                if (childScript != null)
                {
                    childScript.CheckId();

                    childrenGroups.Add(childScript.GetObjGroupSerializedId(), childScript);
                }
            }

            //遍历用户存储的文件，是否是修改了现有的，还是要新建的（则新建之），设置为用户创建的组：
            for (int i = 0; i < groupFilesNames.Length; i++)
            {
                string savedFileName = groupFilesNames[i];
                int savedIndex = int.Parse(savedFileName);

                if (childrenGroups.ContainsKey(savedIndex))
                {
                    childrenGroups[savedIndex].SetReadWriteToUserData();
                }
                else //不存在于场景，需要新建的：
                {
                    //读取文件，获得Group信息
                    //创建一个ObjGroup，并添加到此处
                    string groupInfoStr = FileHelper.ReadFile(C_UserObjGroupFolder, savedFileName);
                    if (string.IsNullOrEmpty(groupInfoStr))
                    {
                        continue;
                    }

                    Vector3 groupPos = VectorHelper.GetVector3FromString(groupInfoStr);
                    var genScript = GenerateGroup(groupPos);
                    genScript.SetReadWriteToUserData();
                }
            }
        }
    }

    /// <summary>
    /// 根据模板生成一个组物体，attach到manager之下，并返回组物体脚本
    /// </summary>
    /// <returns>The group.</returns>
    private SceneObjGroup GenerateGroup(Vector3 genPosition)
    {
        var obj = Instantiate(this.autoDisableGroupTemplate.gameObject,genPosition,Quaternion.identity,m_transform);
        var script = obj.GetComponent<SceneObjGroup>();

        return script;
    }

    /// <summary>
    /// 获得附近的自动关闭的游戏物体组（不一定是最近），如果没有，则将生成一个
    /// </summary>
    /// <returns>The nearest.</returns>
    /// <param name="posSrc">position to detect</param>
    /// <param name="maxRange">Max range.</param>
    private SceneObjGroup GetObjGroup(Vector3 posSrc, float maxRange)
    {
        float sqrMaxRange = maxRange * maxRange;
        SceneObjGroup sceneObjAutoDisable = null;

        for (int i = 0; i < m_transform.childCount; i++)
        {
            var currChild = m_transform.GetChild(i);
            if (currChild.SqrDistanceTo(posSrc) < sqrMaxRange)
            {
                sceneObjAutoDisable = currChild.GetComponent<SceneObjGroup>();
                break;
            }
        }

        return sceneObjAutoDisable;
    }
    #endregion
}
